package cn.miju.unionpay.util;

import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Map;

/**
 * <pre>
 * 银联签名证书工具类
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-03-12 17:52
 */
@Slf4j
public class UnionPayCertUtil {

    private static final Map<String, Cert> CERT_MAP;


    static {
        CERT_MAP = Maps.newHashMap();
    }


    @Data
    @Builder
    @AllArgsConstructor
    public static class Cert {
        /**
         * 证书ID
         */
        private String certId;
        /**
         * 公钥
         */
        private PublicKey publicKey;
        /**
         * 私钥
         */
        private PrivateKey privateKey;
    }

    /**
     * 添加签名证书
     * @param path 签名证书路径
     * @param cert 签名证书信息
     */
    public static void setCert(String path, Cert cert) {
        if (!CERT_MAP.containsKey(path)) {
            CERT_MAP.put(path, cert);
        }
    }

    /**
     * 获取签名证书
     * @param path 签名证书路径
     * @param path 签名证书密码
     */
    public static Cert getCert(String path, String pwd) {
        if (!CERT_MAP.containsKey(path)) {
            FileInputStream fis = null;
            try {
                Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
                KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
                fis = new FileInputStream(path);
                char[] nPassword = null;
                nPassword = null == pwd || "".equals(pwd.trim()) ? null: pwd.toCharArray();
                if (null != ks) {
                    ks.load(fis, nPassword);
                }
                Enumeration<String> aliasenum = null;
                aliasenum = ks.aliases();
                String keyAlias = null;
                if (aliasenum.hasMoreElements()) {
                    keyAlias = aliasenum.nextElement();
                }
                X509Certificate cert = (X509Certificate) ks.getCertificate(keyAlias);
                CERT_MAP.put(path, Cert.builder().
                        certId(cert.getSerialNumber().toString(10)).
                        privateKey((PrivateKey) ks.getKey(keyAlias, pwd.toCharArray())).
                        publicKey(cert.getPublicKey()).
                        build());
            } catch (Exception e) {
                log.error("解析签名文件失败", e);
                throw new RuntimeException("解析签名文件失败");
            } finally {
                if(null!=fis) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return CERT_MAP.get(path);
    }

    /**
     * 移除签名证书
     * @param path 签名证书路径
     */
    public static void removeCert(String path) {
        CERT_MAP.remove(path);
    }

}
